package com.sq.swing.framework.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;


import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import com.sq.swing.framework.exception.dao.DataNotFoundException;
import com.sq.swing.framework.exception.dao.KeyExistException;
import com.sq.swing.util.Assert;


public abstract class BaseDAOImpl<E> extends SqlSessionDaoSupport implements
		BaseDAO<E> {

	public static final String COUNT_POST = "_count";
	public static final String MAPPER_INSERT = "insert";
	public static final String MAPPER_INSERTBATCH = "insertBatch";
	public static final String MAPPER_DELETE = "delete";
	public static final String MAPPER_DELETE_ALL = "deleteAll";
	public static final String MAPPER_DELETEBATCH = "deleteBatch";
	public static final String MAPPER_UPDATE = "update";
	public static final String MAPPER_UPDATEBATCH = "updateBatch";
	public static final String MAPPER_GETOBJECT = "getObject";
	public static final String MAPPER_FINDLIST = "findList";
	public static final String MAPPER_FINDPAGEDLIST = "findPagedList";
	public static final String FINDLISTBYCONDITION = "findListByCondition";
	public static final String MAPPER_SELECTMAP = "selectMap";
	private Class<E> entityClass;

	@SuppressWarnings("unchecked")
	public BaseDAOImpl() {
		Type type = getClass().getGenericSuperclass();
		Type trueType = ((ParameterizedType) type).getActualTypeArguments()[0];
		this.entityClass = (Class<E>) trueType;
	}

	public int delete() throws DataNotFoundException {
		return delete(generateStatement(MAPPER_DELETE));
	}
	
	public int deleteAll() throws DataNotFoundException {
		return delete(generateStatement(MAPPER_DELETE_ALL));
	}

	public int delete(Object parameter) throws DataNotFoundException {
		return delete(generateStatement(MAPPER_DELETE), parameter);
	}

	public int delete(String statement) throws DataNotFoundException {
		return delete(statement, null);
	}

	public int delete(String statement, Object parameter)
			throws DataNotFoundException {
		Assert.notEmpty(statement, "Property statement is required");
		return getSqlSession().delete(statement, parameter);
	}

	public int deleteBatch(List<?> list) throws DataNotFoundException {
		return deleteBatch(generateStatement(MAPPER_DELETEBATCH), list);
	}

	public int deleteBatch(String statement, List<?> list)
			throws DataNotFoundException {
		Assert.notEmpty(statement, "Property statement is required");
		if (list == null || list.isEmpty()) {
			return 0;
		}
		SqlSession sqlSession = getSqlSession();
		for (int i = 0; i < list.size(); i++) {
			sqlSession.delete(statement, list.get(i));
		}
		return list.size();
	}

	public List<E> findList() {
		return findList(generateStatement(MAPPER_FINDLIST));
	}

	public List<E> findList(Object parameter) {
		return findList(generateStatement(MAPPER_FINDLIST), parameter);
	}

	public List<E> findListByCondition(Object parameter) {
		return findList(generateStatement(FINDLISTBYCONDITION), parameter);
	}
	
	public List<E> findList(String statement) {
		return findList(statement, null);
	}

	@SuppressWarnings("unchecked")
	public List<E> findList(String statement, Object parameter) {
		Assert.notEmpty(statement, "Property statement is required");
		return (List<E>) getSqlSession().selectList(statement, parameter);
	}

	public E getObject() {
		return getObject(generateStatement(MAPPER_GETOBJECT));
	}

	public E getObject(Object parameter) {
		return getObject(generateStatement(MAPPER_GETOBJECT), parameter);
	}

	public E getObject(String statement) {
		return getObject(statement, null);
	}

	@SuppressWarnings("unchecked")
	public E getObject(String statement, Object parameter) {
		Assert.notEmpty(statement, "Property statement is required");
		return (E) getSqlSession().selectOne(statement, parameter);
	}

	public int insert() throws KeyExistException {
		return insert(generateStatement(MAPPER_INSERT));
	}

	public int insert(Object parameter) throws KeyExistException {
		return insert(generateStatement(MAPPER_INSERT), parameter);
	}

	public int insert(String statement) throws KeyExistException {
		return insert(statement, null);
	}

	public int insert(String statement, Object parameter)
			throws KeyExistException {
		Assert.notEmpty(statement, "Property statement is required");
		return getSqlSession().insert(statement, parameter);
	}

	public int insertBatch(List<?> list) throws KeyExistException {
		return insertBatch(generateStatement(MAPPER_INSERTBATCH), list);
	}

	public int insertBatch(String statement, List<?> list)
			throws KeyExistException {
		Assert.notEmpty(statement, "Property statement is required");
		if (list == null || list.isEmpty()) {
			return 0;
		}
		SqlSession sqlSession = getSqlSession();
		for (int i = 0; i < list.size(); i++) {
			sqlSession.insert(statement, list.get(i));
		}
		return list.size();
	}

	public Map<?, E> selectMap(String mapKey) {
		return selectMap(generateStatement(MAPPER_SELECTMAP), mapKey);
	}

	public Map<?, E> selectMap(Object parameter, String mapKey) {
		return selectMap(generateStatement(MAPPER_SELECTMAP), parameter, mapKey);
	}

	public Map<?, E> selectMap(String statement, String mapKey) {
		return selectMap(statement, null, mapKey);
	}

	@SuppressWarnings("unchecked")
	public Map<?, E> selectMap(String statement, Object parameter, String mapKey) {
		Assert.notEmpty(statement, "Property statement is required");
		Assert.notEmpty(statement, "Property mapKey is required");
		return getSqlSession().selectMap(statement, parameter, mapKey);
	}

	public int update() throws DataNotFoundException {
		return update(generateStatement(MAPPER_UPDATE));
	}

	public int update(Object parameter) throws DataNotFoundException {
		return update(generateStatement(MAPPER_UPDATE), parameter);
	}

	public int update(String statement) throws DataNotFoundException {
		return update(statement, null);
	}

	public int update(String statement, Object parameter)
			throws DataNotFoundException {
		Assert.notEmpty(statement, "Property statement is required");
		return getSqlSession().update(statement, parameter);
	}

	public int updateBatch(List<?> list) throws DataNotFoundException {
		return updateBatch(generateStatement(MAPPER_UPDATEBATCH), list);
	}

	public int updateBatch(String statement, List<?> list)
			throws DataNotFoundException {
		Assert.notEmpty(statement, "Property statement is required");
		if (list == null || list.isEmpty()) {
			return 0;
		}
		SqlSession sqlSession = getSqlSession();
		for (int i = 0; i < list.size(); i++) {
			sqlSession.update(statement, list.get(i));
		}
		return list.size();
	}

	public String generateStatement(String mapperId) {
		return entityClass.getName() + "." + mapperId;
	}

}
